/*!
  @file data_handler.cpp
  @brief Brief description
  @author Kyohei Otsu <kyon@ac.jaxa.jp>
  @date April, 2013
*/

#include <errno.h>
#include <sys/select.h>
#include <unistd.h>

#include "net/data_handler.h"
#include "core/core.h"

namespace net
{

void DataHandler::init(const int sock, const char *mode)
{
  sock_ = sock;
  fp_ = fdopen(sock, mode);
  //TODO(kyon) error handling

  connected_ = true;
  buf_ = (unsigned char*) malloc(CHUNK_SIZE);
}

void DataHandler::startThreads()
{
  INFO("starting threads");
  int s = pthread_create(&sthread_, NULL, sendData, this);
  int r = pthread_create(&rthread_, NULL, receiveData, this);
  if (s != 0 || r != 0) {
    ERROR("data_handler pthread_create failed");
  }
}

void DataHandler::killThreads()
{
  pthread_cancel(sthread_);
  pthread_cancel(rthread_);
  fclose(fp_);
}

inline void* DataHandler::receiveData(void *_arg)
{
  DataHandler *handler = (DataHandler*) _arg;

  //-- init for select()
  fd_set fds;
  std::tr1::shared_ptr<struct timeval> timeout(new struct timeval); // loop ratio
  timeout->tv_sec = 5;
  timeout->tv_usec = 0;

  while (handler->connected_) 
  {
    //-- set file descriptor
    FD_ZERO(&fds);
    FD_SET(handler->sock(), &fds);

    int ready = select(handler->sock()+1, &fds, NULL, NULL, timeout.get());
    if (errno == EINTR) break; // signal received
    else if (ready < 0) {
      WARN("select error");
      continue;
    }

    if (FD_ISSET(handler->sock(), &fds)) {
      handler->onReceive();
    }

  }
  return NULL;
}

inline void* DataHandler::sendData(void *_arg)
{
  DataHandler *handler = (DataHandler*) _arg;
  for (int i = 0; i < 4; i++) {
  sleep(5);
  if (handler->connected_) 
    handler->onSend();
  }
  return NULL;
}

} // end of namespace
